#ifndef _AMERICO_UTILITIES_H_
#define _AMERICO_UTILITIES_H_

#include <string>
#include <sstream>
#include "Vector.h"

template <typename T>
inline int toInt(const T &aValue)
{
	return static_cast<int>(aValue);
}

template <typename T>
inline float toFloat(const T &aValue)
{
	return static_cast<float>(aValue);
}

template <typename T>
inline unsigned int toUInt(const T &aValue)
{
	return static_cast<unsigned int>(aValue);
}

template <typename T>
inline Vector2<int> toInt(const Vector2<T> &aValue)
{
	return Vector2<int>(static_cast<int>(aValue.x), static_cast<int>(aValue.y));
}

template <typename T>
inline Vector2<float> toFloat(const Vector2<T> &aValue)
{
	return Vector2<float>(static_cast<float>(aValue.x), static_cast<float>(aValue.y));
}

template <typename T>
inline Vector2<unsigned int> toUInt(const Vector2<T> &aValue)
{
	return Vector2<unsigned int>(static_cast<unsigned int>(aValue.x), static_cast<unsigned int>(aValue.y));
}

template <typename T>
inline std::string toString(const T &aValue)
{
	std::stringstream line;
	line << aValue;
	return line.str();
}

template <typename T>
inline T Max(const T &aValue, const T &anotherValue)
{
	return ((aValue<anotherValue)?(anotherValue):(aValue));
}

template <typename T>
inline T Min(const T &aValue, const T &anotherValue)
{
	return ((aValue<anotherValue)?(aValue):(anotherValue));
}

template <typename T>
inline Vector2<T> Max(const Vector2<T> &aValue, const Vector2<T> &anotherValue)
{
	return Vector2f(Max(aValue.x, anotherValue.x), Max(aValue.y, anotherValue.y));
}

template <typename T>
inline T Max(const Vector3<T> &aValue)
{
	return Max(Max(aValue.x, aValue.y), aValue.z);
}

template <typename T>
inline Vector2<T> MaxMin(const Vector2<T> &aValue, const Vector2<T> &anotherValue)
{
	return Vector2f(Max(aValue.x, anotherValue.x), Min(aValue.y, anotherValue.y));
}

template <typename T>
inline Vector2<T> Min(const Vector2<T> &aValue, const Vector2<T> &anotherValue)
{
	return Vector2f(Min(aValue.x, anotherValue.x), Min(aValue.y, anotherValue.y));
}

template <typename T>
inline Vector2<T> MinMax(const Vector2<T> &aValue, const Vector2<T> &anotherValue)
{
	return Vector2f(Min(aValue.x, anotherValue.x), Max(aValue.y, anotherValue.y));
}

template <typename T>
inline T Max(const Vector2<T> &aValue)
{
	return ((aValue.x<aValue.y)?(aValue.y):(aValue.x));
}

template <typename T>
inline T MaxAbs(const Vector2<T> &aValue)
{
	return ((abs(aValue.x)<abs(aValue.y))?(aValue.y):(aValue.x));
}

template <typename T>
inline T Min(const Vector2<T> &aValue)
{
	return ((aValue.x<aValue.y)?(aValue.x):(aValue.y));
}

template <typename T>
void ColorIncrement(const T &aMin, const T &aMax, T &aValue, const float &aDelta)
{
	if (aMin<aMax)
	{
		if (aValue<aMax)
		{
			aValue += 8 * aDelta;
			if(aValue>aMax)
			{
				aValue = aMax;
			}
		}
	}
	else
	{
		if (aValue>aMax)
		{
			aValue -= 8 * aDelta;
			if(aValue<aMax)
			{
				aValue = aMax;
			}
		}
	}
}

template <typename T>
inline T Sqr(const T &aValue)
{
	return (aValue*aValue);
}

template <typename T>
inline void SortMin(T &aValue1, T &aValue2)
{
	if (aValue2<aValue1)
	{
		T temp = aValue1;
		aValue1 = aValue2;
		aValue2 = temp;
	}
}

template <typename T>
inline void SortMax(T &aValue1, T &aValue2)
{
	if (aValue1<aValue2)
	{
		T temp = aValue1;
		aValue1 = aValue2;
		aValue2 = temp;
	}
}

template <typename T>
inline void SortMin(Vector2<T> &aValue1, Vector2<T> &aValue2)
{
	SortMin(aValue1.x, aValue2.x);
	SortMin(aValue1.y, aValue2.y);
}

template <typename T>
inline void SortMax(Vector2<T> &aValue1, Vector2<T> &aValue2)
{
	SortMax(aValue1.x, aValue2.x);
	SortMax(aValue1.y, aValue2.y);
}

#endif